"""
文件管理路由模块
实现文件上传、下载、删除等文件管理相关接口
"""

# 添加项目根目录到Python路径
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

# 导入FastAPI相关组件
from fastapi import APIRouter, UploadFile, File, Form, HTTPException, Depends, status
# 导入文件响应组件
from fastapi.responses import FileResponse, JSONResponse
# 导入Pydantic模型用于数据验证
from pydantic import BaseModel
# 导入类型提示
from typing import List, Optional
# 导入操作系统相关模块
import os
# 导入UUID模块用于生成唯一标识符
import uuid
# 导入pandas用于数据处理
import pandas as pd
# 导入日期时间处理模块
from datetime import datetime
# 导入SQLAlchemy会话
from sqlalchemy.orm import Session

# 导入模型和数据库会话
from utils.models import File as FileModel, get_db
from utils.config import Config

# 创建API路由实例
router = APIRouter(
    prefix="/api/v1/files",  # 路由前缀
    tags=["files"],  # 标签
    responses={404: {"description": "Not found"}},  # 响应定义
)

# 确保上传目录存在，使用统一配置
UPLOAD_DIRECTORY = Config.UPLOAD_FOLDER
os.makedirs(UPLOAD_DIRECTORY, exist_ok=True)

# 数据模型定义
class FileInfo(BaseModel):
    """
    文件信息数据模型
    """
    id: int                      # 文件ID
    filename: str                # 文件名
    filesize: int                # 文件大小
    filetype: str                # 文件类型
    version: float               # 文件版本
    description: Optional[str] = None  # 文件描述
    user_id: int                 # 用户ID
    created_at: datetime         # 创建时间

    class Config:
        from_attributes = True  # 启用ORM模式

class FileListResponse(BaseModel):
    """
    文件列表响应数据模型
    """
    message: str           # 响应消息
    files: List[FileInfo]  # 文件列表

class FileUploadRequest(BaseModel):
    """
    文件上传请求数据模型
    """
    description: Optional[str] = None  # 文件描述
    version: Optional[float] = 1.0     # 文件版本

class FileUploadResponse(BaseModel):
    """
    文件上传响应数据模型
    """
    message: str     # 响应消息
    file_id: int     # 文件ID
    filename: str    # 文件名
    filepath: str    # 文件路径

class FileDeleteResponse(BaseModel):
    """
    文件删除响应数据模型
    """
    message: str  # 响应消息
    file_id: int  # 文件ID

class FilePreviewResponse(BaseModel):
    """
    文件预览响应数据模型
    """
    message: str        # 响应消息
    file_id: int        # 文件ID
    filename: str       # 文件名
    preview_data: dict  # 预览数据
    rows: int           # 行数
    columns: int        # 列数

# 依赖项定义
def get_file_path(file_id: int, db: Session = Depends(get_db)):
    """
    获取文件路径依赖项
    根据文件ID获取文件存储路径
    Args:
        file_id (int): 文件ID
        db (Session): 数据库会话
    Returns:
        str: 文件存储路径
    Raises:
        HTTPException: 当文件未找到时抛出异常
    """
    file_record = db.query(FileModel).filter(FileModel.id == file_id).first()
    if not file_record:
        raise HTTPException(status_code=404, detail="文件未找到")
    return file_record.filepath

# 路由定义
@router.get("/", response_model=FileListResponse)
async def list_files(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    """
    获取文件列表接口
    返回系统中的文件列表（不包括已删除的文件）
    Args:
        skip (int): 跳过的记录数
        limit (int): 限制返回的记录数
        db (Session): 数据库会话
    Returns:
        FileListResponse: 文件列表响应
    """
    files = db.query(FileModel).filter(FileModel.is_deleted == 0).offset(skip).limit(limit).all()
    return {
        "message": "文件列表获取成功",
        "files": files
    }

@router.post("/upload", response_model=FileUploadResponse)
async def upload_file(
    file: UploadFile = File(...),
    description: Optional[str] = Form(None),
    version: Optional[float] = Form(1.0),
    user_id: int = Form(1),  # 实际项目中应从认证信息中获取
    db: Session = Depends(get_db)
):
    """
    上传文件接口
    上传文件并保存到本地存储，同时记录文件元数据到数据库
    Args:
        file (UploadFile): 上传的文件
        description (Optional[str]): 文件描述
        version (Optional[float]): 文件版本
        user_id (int): 用户ID
        db (Session): 数据库会话
    Returns:
        FileUploadResponse: 文件上传响应
    """
    # 生成唯一文件名
    file_extension = os.path.splitext(file.filename)[1]
    unique_filename = f"{uuid.uuid4()}{file_extension}"
    file_path = os.path.join(UPLOAD_DIRECTORY, unique_filename)
    
    # 保存文件
    with open(file_path, "wb") as buffer:
        content = await file.read()
        buffer.write(content)
    
    # 创建文件记录
    file_record = FileModel(
        filename=file.filename,
        filepath=file_path,
        filesize=len(content),
        filetype=file.content_type,
        version=version,
        user_id=user_id,
        description=description
    )
    
    db.add(file_record)
    db.commit()
    db.refresh(file_record)
    
    return {
        "message": "文件上传成功",
        "file_id": file_record.id,
        "filename": file_record.filename,
        "filepath": file_record.filepath
    }

@router.get("/{file_id}", response_class=FileResponse)
async def download_file(file_id: int, db: Session = Depends(get_db)):
    """
    下载文件接口
    根据文件ID下载对应的文件
    Args:
        file_id (int): 文件ID
        db (Session): 数据库会话
    Returns:
        FileResponse: 文件响应
    Raises:
        HTTPException: 当文件未找到或不存在于磁盘上时抛出异常
    """
    file_record = db.query(FileModel).filter(FileModel.id == file_id, FileModel.is_deleted == 0).first()
    if not file_record:
        raise HTTPException(status_code=404, detail="文件未找到")
    
    if not os.path.exists(file_record.filepath):
        raise HTTPException(status_code=404, detail="文件不存在于磁盘上")
    
    return FileResponse(
        path=file_record.filepath,
        filename=file_record.filename,
        media_type=file_record.filetype
    )

@router.delete("/{file_id}", response_model=FileDeleteResponse)
async def delete_file(file_id: int, db: Session = Depends(get_db)):
    """
    删除文件接口（软删除）
    标记文件为已删除状态，不真正删除文件
    Args:
        file_id (int): 文件ID
        db (Session): 数据库会话
    Returns:
        FileDeleteResponse: 文件删除响应
    Raises:
        HTTPException: 当文件未找到时抛出异常
    """
    file_record = db.query(FileModel).filter(FileModel.id == file_id).first()
    if not file_record:
        raise HTTPException(status_code=404, detail="文件未找到")
    
    # 软删除：标记为已删除
    file_record.is_deleted = 1
    db.commit()
    
    # 注意：这里可以选择是否真正删除文件
    # 如果要真正删除文件，可以取消下面的注释
    # if os.path.exists(file_record.filepath):
    #     os.remove(file_record.filepath)
    
    return {
        "message": "文件删除成功",
        "file_id": file_id
    }

@router.get("/{file_id}/info", response_model=FileInfo)
async def get_file_info(file_id: int, db: Session = Depends(get_db)):
    """
    获取文件详细信息接口
    根据文件ID获取文件的详细信息
    Args:
        file_id (int): 文件ID
        db (Session): 数据库会话
    Returns:
        FileInfo: 文件信息
    Raises:
        HTTPException: 当文件未找到时抛出异常
    """
    file_record = db.query(FileModel).filter(FileModel.id == file_id, FileModel.is_deleted == 0).first()
    if not file_record:
        raise HTTPException(status_code=404, detail="文件未找到")
    
    return file_record

@router.post("/{file_id}/version", response_model=FileUploadResponse)
async def create_new_version(
    file_id: int,
    file: UploadFile = File(...),
    description: Optional[str] = Form(None),
    user_id: int = Form(1),  # 实际项目中应从认证信息中获取
    db: Session = Depends(get_db)
):
    """
    创建文件新版本接口
    为指定文件创建新版本
    Args:
        file_id (int): 原文件ID
        file (UploadFile): 新版本文件
        description (Optional[str]): 文件描述
        user_id (int): 用户ID
        db (Session): 数据库会话
    Returns:
        FileUploadResponse: 文件上传响应
    Raises:
        HTTPException: 当原文件未找到时抛出异常
    """
    # 获取原文件信息
    original_file = db.query(FileModel).filter(FileModel.id == file_id, FileModel.is_deleted == 0).first()
    if not original_file:
        raise HTTPException(status_code=404, detail="原文件未找到")
    
    # 生成新版本号
    new_version = round(original_file.version + 0.1, 1)
    
    # 生成唯一文件名
    file_extension = os.path.splitext(file.filename)[1]
    unique_filename = f"{uuid.uuid4()}{file_extension}"
    file_path = os.path.join(UPLOAD_DIRECTORY, unique_filename)
    
    # 保存文件
    with open(file_path, "wb") as buffer:
        content = await file.read()
        buffer.write(content)
    
    # 创建新版本文件记录
    file_record = FileModel(
        filename=original_file.filename,
        filepath=file_path,
        filesize=len(content),
        filetype=file.content_type,
        version=new_version,
        user_id=user_id,
        description=description or original_file.description
    )
    
    db.add(file_record)
    db.commit()
    db.refresh(file_record)
    
    return {
        "message": f"文件新版本创建成功，版本号: {new_version}",
        "file_id": file_record.id,
        "filename": file_record.filename,
        "filepath": file_record.filepath
    }

@router.get("/{file_id}/preview", response_model=FilePreviewResponse)
async def preview_file(file_id: int, rows: int = 10, db: Session = Depends(get_db)):
    """
    预览文件内容接口
    支持CSV、Excel等格式的文件预览
    Args:
        file_id (int): 文件ID
        rows (int): 预览行数
        db (Session): 数据库会话
    Returns:
        FilePreviewResponse: 文件预览响应
    Raises:
        HTTPException: 当文件未找到或预览失败时抛出异常
    """
    # 获取文件信息
    file_record = db.query(FileModel).filter(FileModel.id == file_id, FileModel.is_deleted == 0).first()
    if not file_record:
        raise HTTPException(status_code=404, detail="文件未找到")
    
    if not os.path.exists(file_record.filepath):
        raise HTTPException(status_code=404, detail="文件不存在于磁盘上")
    
    # 根据文件类型进行预览
    try:
        preview_data = {}
        row_count = 0
        col_count = 0
        
        if file_record.filetype in ["text/csv", "application/csv"] or file_record.filename.endswith(".csv"):
            # 处理CSV文件
            df = pd.read_csv(file_record.filepath, nrows=rows)
            preview_data = df.to_dict(orient="records")
            row_count = len(df)
            col_count = len(df.columns)
            
        elif file_record.filetype in ["application/vnd.ms-excel", 
                                      "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] or \
             file_record.filename.endswith((".xls", ".xlsx")):
            # 处理Excel文件
            df = pd.read_excel(file_record.filepath, nrows=rows)
            preview_data = df.to_dict(orient="records")
            row_count = len(df)
            col_count = len(df.columns)
            
        elif file_record.filetype in ["application/json"] or file_record.filename.endswith(".json"):
            # 处理JSON文件
            df = pd.read_json(file_record.filepath)
            # 如果是数组形式的JSON，限制行数
            if isinstance(df, list):
                df = pd.DataFrame(df[:rows])
            preview_data = df.to_dict(orient="records")
            row_count = len(df)
            col_count = len(df.columns)
            
        else:
            # 其他文本文件
            with open(file_record.filepath, "r", encoding="utf-8", errors="ignore") as f:
                lines = f.readlines()[:rows]
                preview_data = {"lines": lines}
                row_count = len(lines)
                col_count = 1
                
        return {
            "message": "文件预览成功",
            "file_id": file_id,
            "filename": file_record.filename,
            "preview_data": preview_data,
            "rows": row_count,
            "columns": col_count
        }
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"文件预览失败: {str(e)}")